package com.df.my_net_game.net.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Admin
 * @class ServerSocket
 * @date 2024/4/3 14:58
 */
public class ServerSocket extends Thread {

    /**
     * 日志
     */
    Logger log = LoggerFactory.getLogger(ServerSocket.class);

    /**
     * boss线程组
     */
    private final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
    /**
     * 工作线程组
     */
    private final NioEventLoopGroup workGroup = new NioEventLoopGroup();
    /**
     * serverBootStrap
     */
    private final ServerBootstrap serverBootStrap = new ServerBootstrap();
    /**
     * name
     */
    private final String name;
    /**
     * port端口号
     */
    private final int port;
    /**
     * channel初始化对象
     */
    private final ChannelInitializer<SocketChannel> channelInitializer;
    /**
     * 启动监听flag
     */
    private boolean startFlag = false;

    public ServerSocket(String name, int port, ChannelInitializer<SocketChannel> channelInitializer) {
        this.name = name;
        this.port = port;
        this.channelInitializer = channelInitializer;
    }

    public ChannelInitializer<SocketChannel> getChannelInitializer() {
        return channelInitializer;
    }

    @Override
    public void run() {
        if (startFlag) {
            return;
        }
        startFlag = true;
        log.info("Listen begin");
        //启动Netty服务
        startNetty();
    }

    /***
     * 启动netty服务
     * @author: Admin
     * @date: 2024/4/3 15:08
     * @return: void
     */
    private void startNetty() {
        try {
            ServerBootstrap server = this.serverBootStrap;
            //Netty 主从Reactor多线程模型
            //option()是提供给NioServerSocketChannel用来接收连接, 也就是Boss线程组,接受客户端的连接
            //childOption()是提供给ServerChanel接收到的连接, 也就是worker线程组-主要用来处理IO逻辑处理
            server.group(this.bossGroup, this.workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(getChannelInitializer())
                    //等待连接通信队列大小,服务器套接字的最大连接数,配置 ServerSocketChannel 的接受连接队列的大小
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //发送接收缓冲器
                    .childOption(ChannelOption.SO_SNDBUF, 2048 * 1024)
                    .childOption(ChannelOption.SO_RCVBUF, 512 * 1024)
                    //TCP处理
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //重用地址
                    .childOption(ChannelOption.SO_REUSEADDR, true)
                    //buffer配置
                    .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator())
                    //池化处理
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
                            new WriteBufferWaterMark(512 * 1024, 2048 * 1024));

            //绑定端口
            ChannelFuture future = server.bind(port);
            future.addListener((ChannelFutureListener) channelFuture -> {
                if (channelFuture.isSuccess()) {
                    log.info(name + " Listen端口 " + port + " 成功");
                } else {
                    log.info(name + " Listen端口 " + port + " 失败");
                }
            });
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            //优雅关机
            close();
        }
    }

    /***
     * 优雅关机
     * @author: Admin
     * @date: 2024/4/3 15:09
     * @return: void
     */
    public void close() {

        bossGroup.shutdownGracefully();
        workGroup.shutdownGracefully();
        System.out.println("Closed Server");
    }
}
